"""Beaker metrics."""
import os

from cki_lib import misc
from cki_lib import yaml
from cki_lib.cronjob import CronJob
from cki_lib.session import get_session
import prometheus_client

SESSION = get_session(__name__)
BEAKER_CONFIG = yaml.load(contents=os.environ.get('BEAKER_CONFIG', ''))


class BeakerMetrics(CronJob):
    """Calculate Beaker metrics."""

    schedule = '*/5 * * * *'

    metric_pool_count = prometheus_client.Gauge(
        'cki_beaker_pool_count',
        'Number of systems in a Beaker pool',
        ['pool']
    )

    metric_system = prometheus_client.Info(
        'cki_beaker_system',
        'Status of a system in Beaker',
        ['system']
    )

    @staticmethod
    def _beaker_get(endpoint):
        """Do the Beaker get request."""
        headers = {"Accept": "application/json"}
        return SESSION.get(
            BEAKER_CONFIG['beaker_url'] + endpoint,
            headers=headers
        ).json()

    @staticmethod
    def login() -> None:
        """Login with Kerberos."""
        SESSION.post(BEAKER_CONFIG['beaker_url'] + '/auth/login_password', json={
            'username': os.environ['BEAKER_USERNAME'],
            'password': os.environ['BEAKER_PASSWORD'],
        })

    def update_pool_count(self):
        """Update the cki_beaker_pool_count metric."""
        for pool in BEAKER_CONFIG.get('pools', []):
            data = self._beaker_get(f'/pools/{pool}')
            self.metric_pool_count.labels(pool).set(
                len(data.get('systems'))
            )

    def update_system(self):
        """Update the cki_beaker_system metric."""
        for system in BEAKER_CONFIG.get('systems', []):
            try:
                data = self._beaker_get(f'/systems/{system}')
            except Exception:  # pylint: disable=broad-except
                self.metric_system.labels(system).info({
                    'status': 'Invalid',
                    'type': 'Machine',
                    'can_reserve': 'true',
                    'recipe_id': '0',
                    'loaned_to': '',
                    'reserved_by': '',
                })
            else:
                self.metric_system.labels(system).info({
                    'status': data.get('status'),
                    'type': data.get('type'),
                    'can_reserve': misc.booltostr(data.get('can_reserve')),
                    'recipe_id': str(misc.get_nested_key(data, 'current_reservation/recipe_id', 0)),
                    'loaned_to': misc.get_nested_key(data, 'current_loan/recipient', ''),
                    'reserved_by': misc.get_nested_key(
                        data, 'current_reservation/user/user_name', ''
                    )
                })

    def run(self, **_):
        """Update the metrics."""
        self.login()
        self.update_pool_count()
        self.update_system()
